/***************************************************************************
 *   oboe.controllers.PhysicsController					*
 *   Copyright (C) 2011 by Felipe Manga					*
 *   lufeboma@gmail.com							*
 *									 *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the	   *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to	*
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:						 *
 *									 *
 *   The above copyright notice and this permission notice shall be	*
 *   included in all copies or substantial portions of the Software.	   *
 *									 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,	   *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF	*
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR	 *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.					   *
 ***************************************************************************/

package oboe.controllers;

import flash.display.DisplayObject;
import oboe.core.SigSlot;
import oboe.functors.ApplyGravitationalForces;

class PhysicsController extends SigSlot
{
private static inline var MAX_SPEED:Float = 100;

private var asset:DisplayObject;
private var friction:Float;
private var rotateToTarget:Bool;
private var velocityX:Float;
private var velocityY:Float;
private var positionX:Float;
private var positionY:Float;

private var forceAcc:ApplyGravitationalForces;


public function new( asset:DisplayObject, rotateToTarget:Bool=false, posX:Float=0, posY:Float=0, friction:Float=0 )
{
	this.asset = asset;
	this.velocityX = 0;
	this.velocityY = 0;
	this.positionX = posX;
	this.positionY = posY;
	this.friction = friction;
	this.rotateToTarget = rotateToTarget;
	this.forceAcc = new ApplyGravitationalForces();
}

public function slot_onAddForceVector( x:Float, y:Float ):Void
{
	this.velocityX += x;
	this.velocityY += y;
}

public function slot_onResetForces():Void
{
	this.velocityX = this.velocityY = 0;
}

public function slot_onReset(posX:Float, posY:Float, friction:Float):Void
{
	this.velocityX = this.velocityY = 0;
	this.positionX = posX;
	this.positionY = posY;
	this.friction = friction;
}

public function slot_onTick( time:Float ):Void
{
	this.forceAcc.reset();
	this.signal("onApplyGravitationalForces", this.forceAcc, this.positionX, this.positionY );
	
	time=0.1;
	
	if (this.forceAcc.collided)
	{
	this.shortSignal("onCollision");
	return;
	}
	
	if (Math.abs(this.velocityX) < MAX_SPEED && Math.abs(this.velocityY) < MAX_SPEED)
	{
	this.velocityX += this.forceAcc.getX() * time;
	this.velocityY += this.forceAcc.getY() * time;
	}
	
	var dx:Float = this.velocityX;
	var dy:Float = this.velocityY;
	
	this.positionY += this.velocityY * time;		
	this.positionX += this.velocityX * time;
	
	var mag:Float = 1/(1+friction*time);
	this.velocityX *= mag;
	this.velocityY *= mag;
	if( this.rotateToTarget && (Math.abs(dx)+Math.abs(dy))>0.1 )
	{
	this.asset.rotationZ = Math.atan2( dx, -dy )/Math.PI*180;
	}
	this.shortSignal("onUpdatePhysics", this.positionX, this.positionY );
}

public function slot_onUpdateCameraPosition( x:Float, y:Float ):Void
{
	this.asset.x = this.positionX-x;
	this.asset.y = this.positionY-y;
}
}